package net.kehuilai.tools;


import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.StandardToStringStyle;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

/**
 * Created by andy,gengzh on 16/12/22.
 */
public class StringTool {

    private static final Pattern R_EMAIL = Pattern.compile("^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$");
    private static final Pattern CHECK_EMAIL = Pattern.compile("^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$");
    private static final Pattern R_PHONE = Pattern.compile("^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$");
    private static final Pattern R_PHONE_CODE = Pattern.compile("^\\d{4}$");
    private static final String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    private static final int ALPLEN = ALPHABET.length();

    public static String formatString(String format, Object... arguments) {
        return String.format(format.replaceAll("\\{\\}", "%s"), arguments);
    }

    public static String formatStringList(String message, List<?> arguments, String delimiter) {
        int size = arguments.size();
        if (size <= 1) {
            return message + arguments.get(0).toString();
        }

        int i;
        StringBuilder builder = new StringBuilder();
        builder.append(message);
        for (i = 0; i < size; i++) {
            if (i > 0)
                builder.append(delimiter);
            builder.append(arguments.get(i).toString());
        }
        return builder.toString();
    }

    public static String stringMultiply(String origin, int size) {
        if (size <= 1) {
            return origin;
        }

        int i;
        StringBuilder builder = new StringBuilder();
        for (i = 0; i < size; i++) {
            builder.append(origin);
        }
        return builder.toString();
    }


    /**
     * 转换字节数组为16进制字串
     *
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     *
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码 32
     *
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String md5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(resultString.getBytes("UTF-8"));
            resultString = byteArrayToHexString(md.digest());
        } catch (Exception ignore) {
        }
        return resultString;
    }

    public static String md5Encode16(String origin) {
        return md5Encode(origin).substring(8, 24);
    }

    public static String md5(String format, Object... arguments) {
        String value = formatString(format, arguments);
        return md5Encode(value);
    }

    public static String md5By16(String format, Object... arguments) {
        String value = formatString(format, arguments);
        return md5Encode16(value);
    }

    // ----------------------------------------------------------------------
    public static String checkSum(String content) {
        if (content == null || content.isEmpty())
            return "";
        return checkSum(content.getBytes()) + "";
    }

    public static String checkSum(byte[] bytes) {
        if (bytes == null || bytes.length == 0)
            return "";
        Checksum checksum = new CRC32();
        checksum.update(bytes, 0, bytes.length);
        return checksum.getValue() + "";
    }

    public static boolean isEmpty(String test) {
        return test == null || test.isEmpty();
    }

    public static boolean checkEmail(String test) {
        if (isEmpty(test)) return false;
        if (test.length() < 6) return false;
        if (!test.contains("@")) return false;

        boolean flag = false;
        try {
            Matcher matcher = R_EMAIL.matcher(test);
            flag = matcher.matches();
        } catch (Exception ignore) {
        }
        return flag;
    }

    public static boolean isInvalid(String test) {
        if (isEmpty(test)) return false;
        if (test.length() < 6) return false;
        if (!test.contains("@")) return false;
        boolean flag = false;
        try {
            Matcher matcher = CHECK_EMAIL.matcher(test);
            flag = matcher.matches();
        } catch (Exception ignore) {
        }
        return flag;
    }

    public static boolean checkPhone(String test) {
        if (isEmpty(test)) return false;
        if (test.length() != 11) return false;
        if (!test.startsWith("1")) return false;

        boolean flag = false;
        try {
            Matcher matcher = R_PHONE.matcher(test);
            flag = matcher.matches();
        } catch (Exception ignore) {
        }
        return flag;
    }

    public static boolean checkPhoneVerificationCode(String test) {
        if (isEmpty(test)) return false;
        if (test.length() != 4) return false;

        boolean flag = false;
        try {
            Matcher matcher = R_PHONE_CODE.matcher(test);
            flag = matcher.matches();
        } catch (Exception ignore) {
        }
        return flag;
    }

    public static String secretPhone(String phone) {
        String secretPhone = "";
        if (phone == null) return secretPhone;

        if (phone.length() < 11) return secretPhone;

        return phone.substring(0, 3) + "****" + phone.substring(7, phone.length());
    }

    public static String getString(Object obj) {
        if (obj == null)
            return "";
        return obj.toString();
    }

    /**
     * 获取一定长度的随机字符串
     *
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String getRandomStrByLen(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static String getMixStrByLen(int length) {
        String base = "ABCDEFGHJKLMNPGRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static String getLetStrByLen(int length) {
        String base = "ABCDEFGHJKLMNPGRSTUVWXYZ";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static String getNumStrByLen(int length) {
        String base = "1234567890";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public static long toLong(String val) {
        long result = 0;
        try {
            result = val == null ? 0 : Long.parseLong(val);
        } catch (NumberFormatException ignore) {
        }
        return result;
    }

    public static boolean strContains(String test, String list, String delimiter) {
        if (isEmpty(delimiter))
            delimiter = ",";

        if (isEmpty(list) || isEmpty(test))
            return false;

        String str = delimiter + list + delimiter;

        return str.contains(delimiter + test + delimiter);
    }

    public static String fldAndValToString(Object o, String[] excludeFields) {

        List<String> datas = new ArrayList<String>();
        StringBuilder builder = new StringBuilder();
        try {
            StandardToStringStyle style = new StandardToStringStyle();
            style.setUseIdentityHashCode(false);
            style.setUseClassName(false);
            style.setContentStart("");
            style.setContentEnd("");
            style.setFieldSeparator("&");

            String data = new ReflectionToStringBuilder(o, style).setExcludeFieldNames(excludeFields).toString();

            String[] strs = data.split("&");

            for (String s : strs) {
                if (s.contains("<null>")) continue;
                datas.add(s);
            }
            Collections.sort(datas);

            for (int i = 0; i < datas.size(); i++) {
                builder.append(datas.get(i));

                if (i < datas.size() - 1) builder.append("&");
            }

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return builder.toString();
    }

    public static String getNumConvertLetGtLen(long num, int len) {

        String let = getNumConvertLet(num);

        if (let.length() >= len) {
            return let;
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(let);

            for (int i = 0; i < len - let.length(); i++) {
                sb.insert(0, 'A');
            }
            return sb.toString();
        }
    }

    public static String getNumConvertLet(long num) {
        StringBuilder sb = new StringBuilder();

        if (num < 26) {
            sb.insert(0, (char) (num + 65));
        } else {
            sb.insert(0, (char) (num % 26 + 65));
            sb.insert(0, getNumConvertLet(num / 26));
        }
        return sb.toString();
    }

    public static long getLetConvertNum(String let) {
        if (let == null || let.equals(""))
            return 0;

        long dist = 0;

        for (char c : let.toCharArray()) {
            int num = c - 65;
            dist = (dist * 26 + num);
        }
        return dist;
    }

    public static String encodeBase62(long original) {

        StringBuilder sb = new StringBuilder();

        sb.insert(0, ALPHABET.charAt((int) original % ALPLEN));

        long div = original / ALPLEN;

        if (div > ALPLEN) {
            sb.insert(0, encodeBase62(div));
        } else {
            sb.insert(0, ALPHABET.charAt((int) div));
        }
        return sb.toString();
    }

    public static long decodeBase62(String base62) {
        if (base62 == null || base62.equals(""))
            return 0;

        long dist = 0;

        for (char c : base62.toCharArray()) {
            int pos = ALPHABET.indexOf(c);
            if (pos == -1) continue;

            dist = (dist * ALPLEN + pos);
        }
        return dist;
    }

    // 判断是否是中文字符
    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION;
    }

    // 判断是否是半角字符
    public static boolean isHalfWidth(char c) {
        return c <= '\u00FF' || '\uFF61' <= c && c <= '\uFFDC' || '\uFFE8' <= c && c <= '\uFFEE';
    }
}
